//
// GPSMapEdit
// (c) Konstantin Galichsky (kg@geopainting.com), 2005-2007
//
// Map view overlapped position cursors.
//

# include "StdAfx.h"
# include "Cursors.h"
# include "Position.h"
# include "Map.h"
# include "fast_floor.h"
# include "Wrappers.h"
# include "Globals.h"

void DrawArrow (HDC _hDC, int _x0, int _y0, float _fAngleInDegrees, int _r, int _w0, int _w1) {
	assert (_w0 < _w1);

	POINT points [7];
	points [0].x = _r;
	points [0].y = 0;
	points [1].x = _r - _w1;
	points [1].y = _w1;
	points [2].x = _r - _w1;
	points [2].y = _w0;
	points [3].x = -_r;
	points [3].y = _w0;
	points [4].x = -_r;
	points [4].y = -_w0;
	points [5].x = _r - _w1;
	points [5].y = -_w0;
	points [6].x = _r - _w1;
	points [6].y = -_w1;

	const float fSin = ::sin (_fAngleInDegrees*c_PI/180);
	const float fCos = ::cos (_fAngleInDegrees*c_PI/180);

	for (size_t c = 0; c < 7; ++ c) {
		const long x = points [c].x;
		const long y = points [c].y;
		points [c].x = _x0 + fast_floor (x*fCos - y*fSin + .5f);
		points [c].y = _y0 + fast_floor (x*fSin + y*fCos + .5f);
	}

	::Polygon (_hDC, points, 7);
}

////////////////////////////////////////////////////

static HFONT g_hfontCursors;

void SetCursorLabelFont (const char * _strFont, int _nSize, bool _bBold, bool _bItalics) {
	if (g_hfontCursors)
		::DeleteObject (g_hfontCursors);

	LOGFONT lf = {
		_nSize, 0, 0, 0,
		_bBold ? FW_BOLD : FW_NORMAL, _bItalics ? TRUE : FALSE, FALSE, FALSE,
		DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
		DEFAULT_QUALITY,
		DEFAULT_PITCH | FF_DONTCARE
	};
	::strcpy (lf.lfFaceName, _strFont);
	g_hfontCursors = ::CreateFontIndirect (& lf);
}

void DestroyCursors () {
	if (g_hfontCursors)
		::DeleteObject (g_hfontCursors);
}

Cursors_t g_Cursors;

COLORREF g_colDefaultCursorColor = c_colBlack;

void DrawCursors (HDC _hDC, const rect_t & _rectVisible) {
	CCritSec::CLock lock (g_cs);

	if (g_Cursors.empty ())
		return;

	for (Cursors_t::const_iterator ic = g_Cursors.begin (); ic != g_Cursors.end (); ++ ic) {
		const CCursor_t & cursor = * ic;
		if (cursor.bHidden)
			continue;

		if (! _rectVisible.Contains (cursor.pt))
			continue;
		const long lX = XToScreen (cursor.pt.x);
		const long lY = YToScreen (cursor.pt.y);

		if (cursor.pIcon) {
			OLE_XSIZE_HIMETRIC hmWidth = 0;
			cursor.pIcon->get_Width (& hmWidth);
			const int nWidth  = ::MulDiv (hmWidth  + 1, ::GetDeviceCaps (_hDC, LOGPIXELSX), 2540);

			OLE_YSIZE_HIMETRIC hmHeight = 0;
			cursor.pIcon->get_Height (& hmHeight);
			const int nHeight = ::MulDiv (hmHeight + 1, ::GetDeviceCaps (_hDC, LOGPIXELSY), 2540);

			const HRESULT hr = cursor.pIcon->Render (
				_hDC,
				lX - cursor.xIcon0, lY - cursor.yIcon0 + nHeight, nWidth, -nHeight,
				0, 0, hmWidth, hmHeight,
				NULL
			);
//			if (FAILED (hr))
//				ErrorMsgBox ("Failed to render icon.");
		} else {
			const HBRUSH hbr = ::CreateSolidBrush (cursor.col);
			const HBRUSH hbrPrev = (HBRUSH) ::SelectObject (_hDC, hbr);

			const HPEN hpen = ::CreatePen (PS_SOLID, 1, cursor.colContour == -1 ? g_colDefaultCursorColor : cursor.colContour);
			const HPEN hpenPrev = (HPEN) ::SelectObject (_hDC, hpen);

			const int c_nR = cursor.nR;
			::Ellipse (_hDC, lX - c_nR, lY - c_nR, lX + c_nR + 1, lY + c_nR + 1);

			if (cursor.bHasHeading) {
				const HBRUSH hbrArrow = ::CreateSolidBrush (cursor.colArrow);
				const HBRUSH hbrPrev2 = (HBRUSH) ::SelectObject (_hDC, hbrArrow);

				const HPEN hpenArrow = ::CreatePen (PS_SOLID, 1, cursor.colArrow);
				const HPEN hpenPrev2 = (HPEN) ::SelectObject (_hDC, hpenArrow);

				DrawArrow (_hDC, lX, lY, cursor.fHeading - 90, c_nR - 1, c_nR/3, c_nR - 1);

				::SelectObject (_hDC, hbrPrev2);
				::DeleteObject (hbrArrow);

				::SelectObject (_hDC, hpenPrev2);
				::DeleteObject (hpenArrow);
			}

			::SelectObject (_hDC, hbrPrev);
			::DeleteObject (hbr);

			::SelectObject (_hDC, hpenPrev);
			::DeleteObject (hpen);
		}

		// Draw text label.
		::SetTextColor (_hDC, cursor.colLabel);
		::SetBkMode    (_hDC, TRANSPARENT);
		::SetTextAlign (_hDC, cursor.uiAlignMask);
		::SelectObject (_hDC, g_hfontCursors ? g_hfontCursors : g_hFont);
		::TextOut (_hDC, lX + cursor.xLabel0, lY + cursor.yLabel0, cursor.strLabel.c_str (), cursor.strLabel.size ());
	}
}

CCursor_t * FindTopmostCursor (int _x, int _y) {
	CCritSec::CLock lock (g_cs);

	if (g_Cursors.empty ())
		return NULL;

	CCursor_t * pCursor = NULL;
	for (Cursors_t::iterator ic = g_Cursors.begin (); ic != g_Cursors.end (); ++ ic) {
		CCursor_t & cursor = * ic;
		if (cursor.bHidden)
			continue;

		const long lX = XToScreen (cursor.pt.x);
		const long lY = YToScreen (cursor.pt.y);

		if (
			lX - 8 < _x && _x < lX + 8 &&
			lY - 8 < _y && _y < lY + 8
		)
			pCursor = & cursor;
	}
	return pCursor;
}

void DeleteCursor (CCursor_t & _cursor) {
	CCritSec::CLock lock (g_cs);

	for (Cursors_t::iterator ic = g_Cursors.begin (); ic != g_Cursors.end (); ++ ic) {
		CCursor_t & cursor = * ic;
		if (& cursor == & _cursor) {
			g_Cursors.erase (ic);
			return;
		}
	}
}